package com.css.listener;

import com.css.listener.interfaces.MouseListener;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinUser;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * -
 * </p>
 *
 * @author css
 * @since 2019/1/9
 */
public class Mouse {
    public static final int WM_MOUSEMOVE = 512;
    private static WinUser.HHOOK hhk;
    private static LowLevelMouseProc mouseHook;
    final static User32 lib = User32.INSTANCE;
    private boolean[] on_off = null;
    private MouseListener mouseListener;

    public Mouse() {
//        run();
    }

    public interface LowLevelMouseProc extends WinUser.HOOKPROC {
        WinDef.LRESULT callback(int nCode, WinDef.WPARAM wParam, MOUSEHOOKSTRUCT lParam);
    }

    public static class MOUSEHOOKSTRUCT extends Structure {
        @Override
        protected List<String> getFieldOrder() {
            List<String> a = new ArrayList<String>();
            a.add("dwExtraInfo");
            a.add("pt");
            a.add("wHitTestCode");
            return a;
        }

        public static class ByReference extends MOUSEHOOKSTRUCT implements
                Structure.ByReference {
        }

        public User32.POINT pt;
        public int wHitTestCode;
        public User32.ULONG_PTR dwExtraInfo;
    }

    public void run() {
        WinDef.HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
        mouseHook = (nCode, wParam, info) -> {
            if (nCode >= 0) {
                if (mouseListener != null) {
                    switch (wParam.intValue()) {
                        case MouseListener.MOVE:
                            mouseListener.move();
                            break;
                        case MouseListener.LEFT_DOWN:
                            mouseListener.leftDown();
                            break;
                        case MouseListener.LEFT_UP:
                            mouseListener.leftUp();
                            break;
                        case MouseListener.RIGHT_DOWN:
                            mouseListener.rightDown();
                            break;
                        case MouseListener.RIGHT_UP:
                            mouseListener.rightUp();
                            break;
                        case MouseListener.ROLLER:
                            mouseListener.roller();
                            break;
                    }
                }
            }
            WinDef.LPARAM lparam = new WinDef.LPARAM();
            return lib
                    .CallNextHookEx(hhk, nCode, wParam, lparam);
        };
        hhk = lib.SetWindowsHookEx(User32.WH_MOUSE_LL, mouseHook, hMod, 0);
        int result;
        WinUser.MSG msg = new WinUser.MSG();
        while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
            if (result == -1) {
                System.err.println("error in get message");
                break;
            } else {
                System.err.println("got message");
                lib.TranslateMessage(msg);
                lib.DispatchMessage(msg);
            }
        }
        lib.UnhookWindowsHookEx(hhk);
    }

    public void setMouseListener(MouseListener mouseListener) {
        this.mouseListener = mouseListener;
    }
}
